﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Caching;
using System.Web;
using System.Collections;
using System.Text.RegularExpressions;

using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
using TRPOP.Common;

namespace TRPOP.Cache
{
    /// <summary>
    /// Cache Manage
    /// </summary>
    public class CacheManage : ICache
    {
        private CacheManager m_CacheBase = CacheFactory.GetCacheManager();

        private const double m_DurationSecond = 60 * 5;

        private const int mintMaxCacheNum = 300;

        private static readonly object lockCacheManage = new object();

        private const string m_AllCacheKeys = "TRPOP_AllCacheKeys";

        #region ICache 成员

        /// <summary>
        /// save  a Cache
        /// </summary>
        /// <param name="strKey">主键</param>
        /// <param name="objValue">cache值</param>
        /// <param name="durationSecond">以秒为单位</param>
        /// <returns></returns>
        public bool Save(string strKey, object objValue, double durationSecond)
        {
            if (strKey.IsEmpty() || objValue == null)
                return false;

            lock (lockCacheManage)
            {
                m_CacheBase.Add(strKey, //key
                                objValue, //value
                                Microsoft.Practices.EnterpriseLibrary.Caching.CacheItemPriority.Normal,
                                null,
                                new AbsoluteTime(TimeSpan.FromSeconds((durationSecond <= 0 ? m_DurationSecond : durationSecond))));
            }

            AddKey(strKey);
            return true;
        }

        /// <summary>remove a cache
        /// </summary>
        /// <param name="strKey">主键</param>
        /// <returns></returns>
        public void Remove(string strKey)
        {
            if (strKey.IsEmpty())
                return;
            if (m_CacheBase.Contains(strKey))
            {
                lock (lockCacheManage)
                {
                    if (m_CacheBase.Contains(strKey))
                    {
                        lock (lockCacheManage)
                        {
                            m_CacheBase.Remove(strKey);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// clear all cache
        /// </summary>
        public void Clear()
        {
            if (m_CacheBase.Count > 0)
            {
                lock (lockCacheManage)
                {
                    if (m_CacheBase.Count > 0)
                    {
                        lock (lockCacheManage)
                        {
                            m_CacheBase.Flush();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// read cache bu key
        /// </summary>
        /// <param name="strKey">主键</param>
        /// <returns></returns>
        public object Read(string strKey)
        {
            if (strKey.IsEmpty())
                return null;
            lock (lockCacheManage)
            {
                return m_CacheBase.GetData(strKey);
            }
        }

        /// <summary>
        /// check if exist a cache
        /// </summary>
        /// <param name="strKey">主键</param>
        /// <returns></returns>
        public bool IsExist(string strKey)
        {
            lock (lockCacheManage)
            {
                return m_CacheBase.Contains(strKey);
            }
        }

        /// <summary>
        /// 根据设置的正则表达式清除缓存对象
        /// </summary>
        /// <param name="pattern">正则表达式</param>
        public void RemoveByRegexp(string pattern)
        {
            if (pattern.IsEmpty())
                return;
            if (m_CacheBase.Contains(m_AllCacheKeys))
            {
                object objKeys = m_CacheBase.GetData(m_AllCacheKeys);
                if (objKeys == null)
                    return;
                foreach (string strTemp in objKeys.ToString().Split('#'))
                {
                    if (strTemp.IsEmpty() || Regex.IsMatch(strTemp, pattern, RegexOptions.IgnoreCase) == false)
                        continue;
                    else
                    {
                        Remove(strTemp);
                    }
                }
            }
        }

        #endregion

        #region private method

        /// <summary>
        /// 添加Key [ 锁定 lockHelperCacheKeys 直接添加key ]
        /// </summary>
        /// <param name="strKey"></param>
        private void AddKey(string strKey)
        {
            if (strKey.IsEmpty())
                return;
            if (m_CacheBase.Contains(strKey))
            {
                FlushCacheKeys();
                lock (lockCacheManage)
                {
                    if (m_CacheBase.Contains(strKey))
                    {
                        lock (lockCacheManage)
                        {
                            string strAllKey = (string)m_CacheBase.GetData(m_AllCacheKeys);
                            if (strAllKey == null)
                            {
                                m_CacheBase.Add(m_AllCacheKeys, "#" + strKey + "#");
                            }
                            else if (strAllKey.ToString().Contains("#" + strKey + "#") == false)
                            {
                                m_CacheBase.Add(m_AllCacheKeys, strAllKey + "#" + strKey + "#");
                            }
                        }
                    }
                }
            }
        }



        /// <summary>
        /// 刷新CacheKeys 刷新Cache
        /// </summary>
        private void FlushCacheKeys()
        {
            if (m_CacheBase.Contains(m_AllCacheKeys) && m_CacheBase.Count >= mintMaxCacheNum)
            {
                lock (lockCacheManage)
                {
                    if (m_CacheBase.Contains(m_AllCacheKeys) && m_CacheBase.Count >= mintMaxCacheNum)
                    {
                        lock (lockCacheManage)
                        {
                            object obj = m_CacheBase.GetData(m_AllCacheKeys);
                            if (obj == null)
                            {
                                m_CacheBase.Add(m_AllCacheKeys, "#");
                            }
                            else
                            {
                                StringBuilder strBuilder = new StringBuilder("#");
                                bool blnRemoveOverFlow = m_CacheBase.Count >= mintMaxCacheNum;
                                int intIndexCahce = 0;
                                int intRemoveCount = m_CacheBase.Count - mintMaxCacheNum + 1;
                                string[] oStrArray = obj.ToString().Split('#');
                                if (oStrArray.Length > 0)
                                {
                                    for (int intIndex = oStrArray.Length - 1; intIndex >= 0; intIndex--)
                                    {
                                        if (string.IsNullOrEmpty(oStrArray[intIndex]) == false && m_CacheBase.Contains(oStrArray[intIndex]))
                                        {
                                            intIndexCahce++;
                                            if (intIndexCahce <= intRemoveCount)
                                                m_CacheBase.Remove(oStrArray[intIndex]);
                                            else
                                                strBuilder.Append(oStrArray[intIndex] + "#");
                                        }
                                    }
                                }
                                m_CacheBase.Add(m_AllCacheKeys, strBuilder.ToString());
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 根据正则删除 
        /// </summary>
        /// <param name="bisDelete">如果bisDelete 才会执行删除</param>
        /// <param name="strDelReg">缓存的正则</param>
        /// <returns></returns>
        private bool RemoveKeysByEnumSubmitResult(bool bisDelete, string strDelReg)
        {
            if (bisDelete)
            {
                RemoveByRegexp(strDelReg);
            }
            return true;
        }

        #endregion

    }
}
